#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
一键 Makefile 生成器 – 跨平台（Linux/Win/mac）
pip install pyside6
"""
import sys, os, pathlib, platform
from PySide6.QtCore import *
from PySide6.QtWidgets import *
from PySide6.QtGui import *

SYSTEM = platform.system()
is_win = SYSTEM == "Windows"

# ---------------------------------------------------------
# 1. 关键修改：模板与最终调通版本完全一致
# ---------------------------------------------------------
MAKE_TPL = """#-----------------------------------------------------------
# .o 文件生成在源文件同目录
#-----------------------------------------------------------
CXX      := g++
CXXFLAGS := -std=c++{std} -O2 -I. {inc_flags} `pkg-config --cflags {pkg}`
LDFLAGS  := `pkg-config --libs {pkg}` -lGL -ldl

SRCS := {src}

OBJS := $(SRCS:.cpp=.o)

TARGET := bin/{name}

all: $(TARGET)

$(TARGET): $(OBJS)
	@mkdir -p bin
	$(CXX) $^ -o $@ $(LDFLAGS)

%.o: %.cpp
	$(CXX) $(CXXFLAGS) -c $< -o $@

clean:
	rm -f $(OBJS) $(TARGET)

.PHONY: all clean
"""


# -------------------- 主窗口 --------------------
class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("Makefile 生成器")
        self.resize(1000, 720)
        self.cfg = {
            "proj_name": "ImGui",
            "cxx_std": "17",
            "pkg_deps": "glfw3",
            # 2. 默认给出完整 SRCS，避免链接缺失
            "src_list": [
                "Imgui_Small.cpp",
                "hpp/imgui.cpp",
                "hpp/imgui_draw.cpp",
                "hpp/imgui_tables.cpp",
                "hpp/imgui_widgets.cpp",
                "hpp/imgui_impl_glfw.cpp",
                "hpp/imgui_impl_opengl3.cpp",
            ],
            "inc_list": [],
        }
        self.status_bar = self.statusBar()
        file_menu = self.menuBar().addMenu("文件")
        file_menu.addAction("退出", self.close)

        central = QWidget()
        self.setCentralWidget(central)
        lay = QHBoxLayout(central)

        scroll = QScrollArea()
        scroll.setWidgetResizable(True)
        scroll.setFixedWidth(360)
        control = QWidget()
        scroll.setWidget(control)
        form = QFormLayout(control)

        self.le_proj = QLineEdit("ImGui")
        form.addRow("工程名:", self.le_proj)

        self.le_cxx = QLineEdit("17")
        self.le_cxx.setValidator(QIntValidator(11, 23))
        form.addRow("C++标准:", self.le_cxx)

        self.le_pkg = QLineEdit("glfw3")
        form.addRow("pkg-config 依赖:", self.le_pkg)

        form.addRow(self._make_list_widget("源码:", "list_src", ext={".cpp", ".c", ".cc", ".cxx"}))
        form.addRow(self._make_list_widget("Include目录:", "list_inc", is_dir=True))

        right = QVBoxLayout()
        self.preview = QPlainTextEdit()
        self.preview.setFont(QFont("Consolas", 9))
        self.preview.setReadOnly(True)
        right.addWidget(self.preview)

        btn_make = QPushButton("生成 Makefile")
        btn_make.clicked.connect(self.save_makefile)
        right.addWidget(btn_make)

        lay.addWidget(scroll)
        lay.addLayout(right, 1)

        for w in (self.le_proj, self.le_cxx, self.le_pkg):
            w.textChanged.connect(lambda: self.refresh())
        for lst in (self.list_src, self.list_inc):
            lst.model().rowsInserted.connect(lambda: self.refresh())
            lst.model().rowsRemoved.connect(lambda: self.refresh())

        self.cfg_to_ui()
        self.refresh()

    # -------------------- 通用列表控件 --------------------
    def _make_list_widget(self, title, attr, is_dir=False, ext=None):
        w = QWidget()
        v = QVBoxLayout(w)
        lst = QListWidget()
        setattr(self, attr, lst)
        lst.setAcceptDrops(True)
        lst.setContextMenuPolicy(Qt.CustomContextMenu)
        lst.customContextMenuRequested.connect(lambda p: self.generic_menu(p, lst))
        lst.dragEnterEvent = lambda e: e.acceptProposedAction() if e.mimeData().hasUrls() else None
        lst.dropEvent = lambda e: [self.add_unique(lst, u.toLocalFile()) for u in e.mimeData().urls()
                                   if (is_dir and pathlib.Path(u.toLocalFile()).is_dir()) or
                                      (not is_dir and pathlib.Path(u.toLocalFile()).is_file())]
        btn = QHBoxLayout()
        btn.addWidget(QPushButton("浏览…", clicked=lambda: self.browse_multi(lst, is_dir, ext)))
        btn.addWidget(QPushButton("清空", clicked=lst.clear))
        btn.addStretch()
        v.addWidget(QLabel(title))
        v.addWidget(lst)
        v.addLayout(btn)
        return w

    def generic_menu(self, pos, lst):
        item = lst.currentItem()
        menu = QMenu()
        if item:
            menu.addAction("删除", lambda: lst.takeItem(lst.row(item)))
        menu.addAction("清空", lst.clear)
        menu.exec(lst.mapToGlobal(pos))

    def browse_multi(self, lst, is_dir, ext):
        if is_dir:
            d = QFileDialog.getExistingDirectory(self, "选择目录")
            if d:
                self.add_unique(lst, d)
        else:
            files, _ = QFileDialog.getOpenFileNames(self, "选择文件", "", "All files (*)")
            for f in files:
                if ext and pathlib.Path(f).suffix.lower() not in ext:
                    continue
                self.add_unique(lst, f)

    def add_unique(self, lst, path):
        path = os.path.relpath(path, start=pathlib.Path.cwd()).replace("\\", "/")
        if not lst.findItems(path, Qt.MatchExactly):
            lst.addItem(path)

    # -------------------- 配置同步 --------------------
    def ui_to_cfg(self):
        self.cfg["proj_name"] = self.le_proj.text().strip()
        self.cfg["cxx_std"] = self.le_cxx.text().strip()
        self.cfg["pkg_deps"] = self.le_pkg.text().strip()
        self.cfg["src_list"] = [self.list_src.item(i).text() for i in range(self.list_src.count())]
        self.cfg["inc_list"] = [self.list_inc.item(i).text() for i in range(self.list_inc.count())]

    def cfg_to_ui(self):
        self.le_proj.setText(self.cfg["proj_name"])
        self.le_cxx.setText(self.cfg["cxx_std"])
        self.le_pkg.setText(self.cfg["pkg_deps"])
        self.list_src.clear()
        self.list_src.addItems(self.cfg["src_list"])
        self.list_inc.clear()
        self.list_inc.addItems(self.cfg["inc_list"])

    # -------------------- 实时预览 --------------------
    def refresh(self, root=None):
        self.ui_to_cfg()
        if root is None:
            root = pathlib.Path.cwd()
        else:
            root = pathlib.Path(root)

        srcs = [self.list_src.item(i).text() for i in range(self.list_src.count())]
        # 3. 不再替换路径，保持原样
        incs = [self.list_inc.item(i).text() for i in range(self.list_inc.count())]
        inc_flags = " ".join(f"-I{p}" for p in incs)

        txt = MAKE_TPL.format(
            name=self.cfg["proj_name"],
            std=self.cfg["cxx_std"],
            pkg=self.cfg["pkg_deps"],
            inc_flags=inc_flags,
            src=" \\\n    ".join(srcs),
        )
        self.preview.setPlainText(txt)

    # -------------------- 保存 --------------------
    def save_makefile(self):
        if not self.cfg["src_list"]:
            QMessageBox.warning(self, "提示", "源码列表为空")
            return
        path, _ = QFileDialog.getSaveFileName(self, "保存 Makefile", "Makefile")
        if not path:
            return
        self.refresh(pathlib.Path(path).parent)
        try:
            with open(path, "w", encoding="utf-8") as f:
                f.write(self.preview.toPlainText())
            QMessageBox.information(self, "完成", f"Makefile 已保存至\n{path}")
            self.status_bar.showMessage("✅ Makefile 已保存")
        except Exception as e:
            QMessageBox.critical(self, "写入失败", str(e))


# -------------------- 启动 --------------------
if __name__ == "__main__":
    app = QApplication(sys.argv)
    w = MainWindow()
    w.show()
    sys.exit(app.exec())
